/*-----------------------------------------------------------------------------
	The contents of this file are subject to the Mozilla Public License
	Version 1.1 (the "License"); you may not use this file except in
	compliance with the License. You may obtain a copy of the License at
	http://www.mozilla.org/MPL/
	
	Software distributed under the License is distributed on an "AS IS"
	basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the
	License for the specific language governing rights and limitations
	under the License.
	
	The Original Code is Fever Framework code.
	
	The Initial Developer of the Original Code is Romain Ecarnot.
	Portions created by Initial Developer are Copyright (C) 2006
	the Initial Developer. All Rights Reserved.
	
	Contributor(s):
	
	Unless required by applicable law or agreed to in writing, software
	distributed under the License is distributed on an "AS IS" BASIS,
	WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
	See the License for the specific language governing permissions and
	limitations under the License.
-----------------------------------------------------------------------------*/

import com.bourre.commands.Delegate;
import com.bourre.events.DynBasicEvent;
import com.bourre.events.EventType;

import fever.app.context.abstract.Dialog;
import fever.app.context.abstract.IDialog;
import fever.commands.JSCommand;
import fever.commands.JSMethodName;
import fever.data.file.FileFilterCollection;
import fever.events.FeverController;
import fever.exception.RuntimeException;

/**
 * Dialog management using browser context.
 * 
 * <p>Some methods are Asynchronous; don't forget to define callback parameter 
 * for these methods.
 * 
 * @author Romain Ecarnot
 */
class fever.app.context.browser.BrowserDialog extends Dialog implements IDialog
{
	//-------------------------------------------------------------------------
	// Private properties
	//-------------------------------------------------------------------------
	
	private static var confirmMETHOD : JSMethodName = new JSMethodName( "openConfirm" );
	private static var alertMETHOD : JSMethodName = new JSMethodName( "openAlert" );
	
	private var _confirm : JSCommand;
	private var _alert : JSCommand;
	
	
	//-------------------------------------------------------------------------
	// Public Properties
	//-------------------------------------------------------------------------
	
	/** 
	 * Event type called to open a 'FileOpen' dialog in  
	 * {@link fever.app.context.browser.BrowserContext} context.<br />
	 */
	public static var onShowFileOpenDialogEVENT : EventType = new EventType( 'onShowFileOpenDialog');
	
	/** 
	 * Event type called to open a 'FileSave' dialog in  
	 * {@link fever.app.context.browser.BrowserContext} context.<br />
	 */
	public static var onShowFileSaveDialogEVENT : EventType = new EventType( 'onShowFileSaveDialog');
	
	/** 
	 * Event type called to open a 'BrowseFolder' dialog in  
	 * {@link fever.app.context.browser.BrowserContext} context.<br />
	 */
	public static var onShowBrowseFolderDialogEVENT : EventType = new EventType( 'onShowBrowseFolderDialog');
	
	/** 
	 * Event type called to open a 'confirm' dialog in  
	 * {@link fever.app.context.browser.BrowserContext} context.<br />
	 */
	public static var onOpenConfirmDialogEVENT : EventType = new EventType( 'onOpenConfirmDialog');
	
	/** 
	 * Event type called to open a 'alert' dialog in  
	 * {@link fever.app.context.browser.BrowserContext} context.<br />
	 */
	public static var onOpenAlertDialogEVENT : EventType = new EventType( 'onOpenAlertDialog');
	
	/** 
	 * Event type called to open a 'message' dialog in  
	 * {@link fever.app.context.browser.BrowserContext} context.<br />
	 */
	public static var onOpenMessageDialogEVENT : EventType = new EventType( 'onOpenMessageDialog');
	
	
	//-------------------------------------------------------------------------
	// Public API
	//-------------------------------------------------------------------------
	
	/**
	 * Constructor.
	 */
	public function BrowserDialog()
	{
		super();
		
		_initJSCommand();
	}
	
	/**
	 * Opens a File <strong>open</strong> chooser dialog.
	 * 
	 * <p>If {@code handler} is {@code undefined} throws a 
	 * {@link fever.exception.RuntimeException} exeption as this method can't be 
	 * executed in synchronous mode.
	 * 
	 * <p>As we need a complex UI to display a 'FileOpen' dialog, <strong>Fever</strong> 
	 * not contain any basic implementation.<br />
	 * You have to associate your own command to {@link #onShowFileOpenDialogEVENT} event type using 
	 * the {@link fever.events.FeverController} front controller.<br />
	 * For example, if you use the available implementation in <strong>FvAsWing</strong> framework : 
	 * {@code 
	 *   FeverController.getInstance().push( BrowserDialog.onShowFileOpenDialogEVENT, new FvShowFileOpenDialog() );
	 * }
	 * 
	 * <p>If no command is found, throws a {@link fever.exception.RuntimeException} exeption.
	 * 
	 * @param caption ( optional ) Dialog's title
	 * @param filter ( optional ) File filter list to apply ( default use All acceptable files *.* )
	 * @param multipleSelect ( optional ) {@code true} to enable multiple files selections in dialog
	 * @param handler Callback to activate when result is received
	 * 
	 * @return Nothing as this method is asynchronous in browser context.<br />
	 * {@code handler} must be defined to retreive selection result.
	 */
	public function showFileOpenDialog( caption : String, filterList : FileFilterCollection, multipleSelect : Boolean, handler : Delegate ) : String
	{
		if( handler )
		{
			var o : FeverController = FeverController.getInstance();
		
			if( o.isRegistred( onShowFileOpenDialogEVENT ) )
			{
				var event : DynBasicEvent = new DynBasicEvent( onShowFileOpenDialogEVENT );
				event.caption = caption;
				event.filter = filterList;
				event.multipleSelect = multipleSelect;
				event.callback = handler;
				o.broadcastEvent ( event );
			}	
			else
			{
				throw new RuntimeException( 'no command is associated with ' + onShowFileOpenDialogEVENT + ' event type' );
				return null;
			}
		}
		else
		{
			throw new RuntimeException( '.showFileOpenDialog() is Asynchronous in browser context and callback is undefined' );
		}
	}
	
	/**
	 * Opens a File <strong>save</strong> chooser dialog.
	 * 
	 * <p>If {@code handler} is {@code undefined} throws a 
	 * {@link fever.exception.RuntimeException} exeption as this method can't be 
	 * executed in synchronous mode.
	 * 
	 * <p>As we need a complex UI to display a 'FileSave' dialog, <strong>Fever</strong> 
	 * not contain any basic implementation.<br />
	 * You have to associate your own command to {@link #onShowFileSaveDialogEVENT} event type using 
	 * the {@link fever.events.FeverController} front controller.<br />
	 * For example, if you use the available implementation in <strong>FvAsWing</strong> framework : 
	 * {@code 
	 *   FeverController.getInstance().push( BrowserDialog.onShowFileSaveDialogEVENT, new FvShowFileSaveDialog() );
	 * }
	 * 
	 * <p>If no command is found, throws a {@link fever.exception.RuntimeException} exeption.
	 * 
	 * @param caption ( optional ) Dialog's title
	 * @param filter ( optional ) File filter to apply ( default use All acceptable files *.* )
	 * @param fileName ( optional ) default filename used to populate "filename" dialog's field
	 * @param handler Callback to activate when result is received
	 * 
	 * @return Nothing as this method is asynchronous in browser context.<br />
	 * {@code handler} must be defined to retreive selection result.
	 */
	public function showFileSaveDialog( caption : String, filterList : FileFilterCollection, fileName : String, handler : Delegate ) : String
	{
		if( handler )
		{
			var o : FeverController = FeverController.getInstance();
		
			if( o.isRegistred( onShowFileSaveDialogEVENT ) )
			{
				var event : DynBasicEvent = new DynBasicEvent( onShowFileSaveDialogEVENT );
				event.caption = caption;
				event.filter = filterList;
				event.filename = fileName;
				event.callback = handler;
				o.broadcastEvent ( event );
			}	
			else
			{
				throw new RuntimeException( 'no command is associated with ' + onShowFileSaveDialogEVENT + ' event type' );
				return null;
			}
		}
		else
		{
			throw new RuntimeException( '.showFileSaveDialog() is Asynchronous in browser context and callback is undefined' );
		}
	}
	
	/**
	 * Opens a <strong>Browse folder</strong> dialog.
	 * 
	 * <p>If {@code handler} is {@code undefined} throws a 
	 * {@link fever.exception.RuntimeException} exeption as this method can't be 
	 * executed in synchronous mode.
	 * 
	 * <p>As we need a complex UI to display a 'Browse folder' dialog, <strong>Fever</strong> 
	 * not contain any basic implementation.<br />
	 * You have to associate your own command to opens a Browse folder dialog using 
	 * the {@link fever.events.FeverController} front controller.<br />
	 * For example, if you use the available implementation in <strong>FvAsWing</strong> framework : 
	 * {@code 
	 *   FeverController.getInstance().push( BrowserDialog.onShowBrowseFolderDialogEVENT, new FvShowBrowseFolderDialog() );
	 * }
	 * 
	 * <p>If no command is found, throws a {@link fever.exception.RuntimeException} exeption.
	 * 
	 * @param caption ( optional ) Dialog's title
	 * @param handler Callback to activate when result is received
	 * 
	 * @return Nothing as this method is asynchronous in browser context.<br />
	 * {@code handler} must be defined to retreive selection result.
	 */
	public function showBrowseFolderDialog( caption : String, handler : Delegate ) : String
	{
		if( handler )
		{
			var o : FeverController = FeverController.getInstance();
		
			if( o.isRegistred( onShowBrowseFolderDialogEVENT ) )
			{
				var event : DynBasicEvent = new DynBasicEvent( onShowBrowseFolderDialogEVENT );
				event.caption = caption;
				event.callback = handler;
				o.broadcastEvent ( event );
			}	
			else
			{
				throw new RuntimeException( 'no command is associated with ' + onShowBrowseFolderDialogEVENT + ' event type' );
				return null;
			}
		}
		else
		{
			throw new RuntimeException( '.showBrowseFolderDialog() is Asynchronous in browser context and callback is undefined' );
		}
	}
	
	/**
	 * Opens a <strong>confirm</strong> dialog.
	 * 
	 * <p>If {@code handler} is {@code undefined} use the synchronous method ( js command coupling 
	 * with ExternalInterface ), so result is directly return.
	 * 
	 * <p>If {@code handler} is defined, dispatchs the {@link #onOpenConfirmDialogEVENT} event throw 
	 * {@link fever.events.FeverController} front controller.<br />
	 * You must associated command with this event type to use your own confirm dialog.<br />
	 * For example, if you use the available implementation in <strong>FvAsWing</strong> framework :
	 * {@code
	 *   FeverController.getInstance().push( BrowserDialog.onOpenConfirmDialogEVENT, new FvOpenConfirmDialog() );
	 * }
	 * 
	 * @param caption Dialog message
	 * @param ( optional ) handler Callback to activate when command is Asynchronous
	 * 
	 * @return {@code true} if user click on 'ok' button, otherwise {@code false} ( in synchronous mode 
	 * of course )
	 */
	public function confirm( caption : String, handler : Delegate ) : Boolean
	{
		var o : FeverController = FeverController.getInstance();
		
		if( handler && o.isRegistred( onOpenConfirmDialogEVENT ) )
		{
			var event : DynBasicEvent = new DynBasicEvent( onOpenConfirmDialogEVENT );
			event.message = caption;
			event.callback = handler;
			o.broadcastEvent ( event );
		}
		else
		{
			var b : Boolean = _confirm.call( caption );
			
			if( handler == null ) return b;
			else
			{
				handler.addArguments( b );
				handler.execute();	
			}
		}
	}
	
	/**
	 * Opens a <strong>alert</strong> dialog.
	 * 
	 * <p>If a command is associated to {@link #onOpenAlertDialogEVENT} event type in 
	 * {@link fever.events.FeverController} front controller, command is executed.<br />
	 * Either use the basic synchronous method ( 'alert' javascript method coupled with ExternalInterface ).
	 * <br />
	 * For example, if you use the available implementation in <strong>FvAsWing</strong> framework :
	 * {@code
	 *   FeverController.getInstance().push( BrowserDialog.onOpenAlertDialogEVENT, new FvOpenAlertDialog() );
	 * }
	 * 
	 * @param caption Dialog message
	 * @param ( optional ) handler Callback to activate when command is Asynchronous
	 */
	public function alert( caption : String, handler : Delegate ) : Void
	{
		var o : FeverController = FeverController.getInstance();
		
		if( o.isRegistred( onOpenAlertDialogEVENT ) )
		{
			var event : DynBasicEvent = new DynBasicEvent( onOpenAlertDialogEVENT );
			event.message = caption;
			event.callback = handler;
			o.broadcastEvent ( event );
		}
		else
		{
			_alert.call( caption );
		
			if( handler ) handler.execute();
		}
	}
	
	/**
	 * Opens a <strong>alert</strong> dialog.
	 * 
	 * <p>If a command is associated to {@link #onOpenMessageDialogEVENT} event type in 
	 * {@link fever.events.FeverController} front controller, command is executed.<br />
	 * Either use the basic synchronous method ( 'alert' javascript method coupled with ExternalInterface ).
	 * <br />
	 * For example, if you use the available implementation in <strong>FvAsWing</strong> framework :
	 * {@code
	 *   FeverController.getInstance().push( BrowserDialog.onOpenMessageDialogEVENT, new FvOpenMessageDialog() );
	 * }
	 * 
	 * @param caption Dialog message
	 * @param ( optional ) handler Callback to activate when command is Asynchronous
	 */
	public function message( caption : String, handler : Delegate ) : Void
	{
		var o : FeverController = FeverController.getInstance();
		
		if( o.isRegistred( onOpenMessageDialogEVENT ) )
		{
			var event : DynBasicEvent = new DynBasicEvent( onOpenMessageDialogEVENT );
			event.message = caption;
			event.callback = handler;
			o.broadcastEvent ( event );
		}
		else
		{
			_alert.call( caption );
		
			if( handler ) handler.execute();
		}
	}
	
	
	//-------------------------------------------------------------------------
	// Private implementation
	//-------------------------------------------------------------------------
		
	private function _initJSCommand() : Void
	{
		_alert = new JSCommand( 
				alertMETHOD,
				"( caption ){ return alert( caption ); }"
		);
		
		_confirm = new JSCommand( 
			confirmMETHOD,
			"( caption ){ return confirm( caption ); }"
		);
	}
}